package com.powernode.order.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.powernode.common.constant.RedisConstant;
import com.powernode.common.execption.PowerException;
import com.powernode.common.result.ResultCodeEnum;
import com.powernode.model.entity.order.*;
import com.powernode.model.enums.OrderStatus;
import com.powernode.model.form.order.OrderInfoForm;
import com.powernode.model.form.order.StartDriveForm;
import com.powernode.model.form.order.UpdateOrderBillForm;
import com.powernode.model.form.order.UpdateOrderCartForm;
import com.powernode.model.vo.order.CurrentOrderInfoVo;
import com.powernode.order.mapper.OrderBillMapper;
import com.powernode.order.mapper.OrderInfoMapper;
import com.powernode.order.mapper.OrderProfitSharingMapper;
import com.powernode.order.mapper.OrderStatusLogMapper;
import com.powernode.order.service.OrderInfoService;
import com.powernode.order.service.OrderMonitorService;
import jakarta.annotation.Resource;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Resource
    private OrderStatusLogMapper orderStatusLogMapper;
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private OrderInfoMapper orderInfoMapper;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private OrderMonitorService orderMonitorService;
    @Resource
    private OrderBillMapper orderBillMapper;
    @Resource
    private OrderProfitSharingMapper orderProfitSharingMapper;

    /**
     * 客户端“当前订单”允许的状态集合
     */
    private static final List<Integer> CUSTOMER_STATUSES = Arrays.asList(
            OrderStatus.ACCEPTED.getStatus(),
            OrderStatus.DRIVER_ARRIVED.getStatus(),
            OrderStatus.UPDATE_CART_INFO.getStatus(),
            OrderStatus.START_SERVICE.getStatus(),
            OrderStatus.END_SERVICE.getStatus(),
            OrderStatus.UNPAID.getStatus()
    );

    /**
     * 司机端“当前订单”允许的状态集合
     */
    private static final List<Integer> DRIVER_STATUSES = Arrays.asList(
            OrderStatus.ACCEPTED.getStatus(),
            OrderStatus.DRIVER_ARRIVED.getStatus(),
            OrderStatus.UPDATE_CART_INFO.getStatus(),
            OrderStatus.START_SERVICE.getStatus(),
            OrderStatus.END_SERVICE.getStatus()
    );

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Long addOrderInfo(OrderInfoForm orderInfoForm) {
        // 添加一个订单
        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderInfoForm, orderInfo);
        // 创建新的订单号
        String orderNo = UUID.randomUUID().toString().replaceAll("-", "");
        // 设置为等待接单状态
        orderInfo.setStatus(OrderStatus.WAITING_ACCEPT.getStatus());
        orderInfo.setOrderNo(orderNo);
        orderInfoMapper.insert(orderInfo);
        // 记录日志
        OrderStatusLog orderStatusLog = new OrderStatusLog();
        orderStatusLog.setOrderId(orderInfo.getId());
        orderStatusLog.setOrderStatus(orderInfo.getStatus());
        orderStatusLog.setOperateTime(new Date());
        orderStatusLogMapper.insert(orderStatusLog);
        // 把当前订单状态添加到redis一份，用来描述该订单是否被接单
        redisTemplate.opsForValue().set(
                RedisConstant.ORDER_ACCEPT_MARK + orderInfo.getId(),
                "0",
                RedisConstant.ORDER_ACCEPT_MARK_EXPIRES_TIME,
                TimeUnit.MINUTES
        );
        return orderInfo.getId();
    }

    /**
     * 查询订单状态
     */
    @Override
    public Integer queryOrderStatus(Long orderId) {
        OrderInfo selectOne = orderInfoMapper.selectOne(new LambdaQueryWrapper<OrderInfo>()
                .select(OrderInfo::getStatus)
                .eq(OrderInfo::getId, orderId)
        );
        if (null == selectOne)
            // 返回null，feign解析会抛出异常，给默认值，后续会用
            return OrderStatus.NULL_ORDER.getStatus();
        return selectOne.getStatus();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean robNewOrder(Long driverId, Long orderId) {
        RLock rLock = redissonClient.getLock(RedisConstant.ROB_NEW_ORDER_LOCK + orderId);
        try {
            // 抢单成功或取消订单，都会删除该key，redis判断，减少数据库压力
            if (!redisTemplate.hasKey(RedisConstant.ORDER_ACCEPT_MARK + orderId))
                // 抢单失败
                throw new PowerException(ResultCodeEnum.COB_NEW_ORDER_FAIL);
            boolean triedLock = rLock.tryLock(
                    RedisConstant.ROB_NEW_ORDER_LOCK_WAIT_TIME,
                    RedisConstant.ROB_NEW_ORDER_LOCK_LEASE_TIME,
                    TimeUnit.MINUTES
            );
            if (triedLock) {
                if (!redisTemplate.hasKey(RedisConstant.ORDER_ACCEPT_MARK + orderId))
                    // 抢单失败
                    throw new PowerException(ResultCodeEnum.COB_NEW_ORDER_FAIL);
                // 修改订单状态及配送员id
                OrderInfo orderInfo = new OrderInfo();
                orderInfo.setId(orderId);
                orderInfo.setStatus(OrderStatus.ACCEPTED.getStatus());
                orderInfo.setAcceptTime(new Date());
                orderInfo.setDriverId(driverId);
                int rows = orderInfoMapper.updateById(orderInfo);
                if (rows != 1)
                    // 抢单失败
                    throw new PowerException(ResultCodeEnum.COB_NEW_ORDER_FAIL);
                // 记录日志
                OrderStatusLog orderStatusLog = new OrderStatusLog();
                orderStatusLog.setOrderStatus(orderInfo.getStatus());
                orderStatusLog.setOrderId(orderInfo.getId());
                orderStatusLog.setOperateTime(new Date());
                orderStatusLogMapper.insert(orderStatusLog);
                // 抢单完成后，把该订单标识删除掉
                redisTemplate.delete(RedisConstant.ORDER_ACCEPT_MARK + orderInfo.getId());
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException(e);
        } finally {
            // 防止误解锁：只在当前线程持有锁时解锁
            if (rLock.isHeldByCurrentThread())
                rLock.unlock();
        }
        return true;
    }

    @Override
    public CurrentOrderInfoVo searchCustomerCurrentOrder(Long customerId) {
        return findLatestCurrentOrder(customerId, false);
    }

    @Override
    public CurrentOrderInfoVo searchDriverCurrentOrder(Long driverId) {
        return findLatestCurrentOrder(driverId, true);
    }

    /**
     * 查找“最新的当前订单”并封装为CurrentOrderInfoVo
     */
    private CurrentOrderInfoVo findLatestCurrentOrder(Long principalId, boolean byDriver) {
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        if (byDriver) {
            queryWrapper.eq(OrderInfo::getDriverId, principalId);
            queryWrapper.in(OrderInfo::getStatus, DRIVER_STATUSES);
        } else {
            queryWrapper.eq(OrderInfo::getCustomerId, principalId);
            queryWrapper.in(OrderInfo::getStatus, CUSTOMER_STATUSES);
        }
        // 只查需要的字段，按id倒序取最新一条
        queryWrapper
                .select(OrderInfo::getId, OrderInfo::getStatus)
                .orderByDesc(OrderInfo::getId)
                .last("limit 1");
        OrderInfo orderInfo = orderInfoMapper.selectOne(queryWrapper);
        CurrentOrderInfoVo vo = new CurrentOrderInfoVo();
        if (orderInfo != null) {
            vo.setStatus(orderInfo.getStatus());
            vo.setOrderId(orderInfo.getId());
            vo.setIsHasCurrentOrder(true);
        } else
            vo.setIsHasCurrentOrder(false);
        return vo;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean driverArriveStartLocation(Long orderId, Long driverId) {
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderInfo::getId, orderId);
        queryWrapper.eq(OrderInfo::getDriverId, driverId);
        OrderInfo updateOrderInfo = new OrderInfo();
        updateOrderInfo.setStatus(OrderStatus.DRIVER_ARRIVED.getStatus());
        updateOrderInfo.setArriveTime(new Date());
        // 只能更新自己的订单
        int row = orderInfoMapper.update(updateOrderInfo, queryWrapper);
        if (row == 1) {
            // 记录日志，可以单独提取出来
            OrderStatusLog orderStatusLog = new OrderStatusLog();
            orderStatusLog.setOrderStatus(OrderStatus.DRIVER_ARRIVED.getStatus());
            orderStatusLog.setOrderId(orderId);
            orderStatusLog.setOperateTime(new Date());
            orderStatusLogMapper.insert(orderStatusLog);
        } else
            throw new PowerException(ResultCodeEnum.UPDATE_ERROR);
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean updateOrderCart(UpdateOrderCartForm updateOrderCartForm) {
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderInfo::getId, updateOrderCartForm.getOrderId());
        queryWrapper.eq(OrderInfo::getDriverId, updateOrderCartForm.getDriverId());
        OrderInfo updateOrderInfo = new OrderInfo();
        BeanUtils.copyProperties(updateOrderCartForm, updateOrderInfo);
        updateOrderInfo.setStatus(OrderStatus.UPDATE_CART_INFO.getStatus());
        // 只能更新自己的订单
        int row = orderInfoMapper.update(updateOrderInfo, queryWrapper);
        if (row == 1) {
            // 记录日志，可以单独提取出来
            OrderStatusLog orderStatusLog = new OrderStatusLog();
            orderStatusLog.setOrderStatus(OrderStatus.UPDATE_CART_INFO.getStatus());
            orderStatusLog.setOrderId(updateOrderCartForm.getOrderId());
            orderStatusLog.setOperateTime(new Date());
            orderStatusLogMapper.insert(orderStatusLog);
        } else
            throw new PowerException(ResultCodeEnum.UPDATE_ERROR);
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean startDrive(StartDriveForm startDriveForm) {
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderInfo::getId, startDriveForm.getOrderId());
        queryWrapper.eq(OrderInfo::getDriverId, startDriveForm.getDriverId());
        OrderInfo updateOrderInfo = new OrderInfo();
        updateOrderInfo.setStatus(OrderStatus.START_SERVICE.getStatus());
        updateOrderInfo.setStartServiceTime(new Date());
        // 只能更新自己的订单
        int row = orderInfoMapper.update(updateOrderInfo, queryWrapper);
        if (row == 1) {
            // 记录日志
            this.log(startDriveForm.getOrderId(), OrderStatus.START_SERVICE.getStatus());
        } else
            throw new PowerException(ResultCodeEnum.UPDATE_ERROR);
        // 初始化订单监控统计数据
        OrderMonitor orderMonitor = new OrderMonitor();
        orderMonitor.setOrderId(startDriveForm.getOrderId());
        orderMonitorService.saveOrderMonitor(orderMonitor);
        return true;
    }

    /**
     * 记录订单状态日志处理
     */
    private void log(Long orderId, Integer orderStatus) {
        // 记录日志，可以单独提取出来
        OrderStatusLog orderStatusLog = new OrderStatusLog();
        orderStatusLog.setOrderStatus(orderStatus);
        orderStatusLog.setOrderId(orderId);
        orderStatusLog.setOperateTime(new Date());
        orderStatusLogMapper.insert(orderStatusLog);
    }

    @Override
    public Long getOrderNumByTime(String startTime, String endTime) {
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.ge(OrderInfo::getStartServiceTime, startTime);
        queryWrapper.lt(OrderInfo::getStartServiceTime, endTime);
        return orderInfoMapper.selectCount(queryWrapper);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean endDrive(UpdateOrderBillForm updateOrderBillForm) {
        // 更新订单信息
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderInfo::getId, updateOrderBillForm.getOrderId());
        queryWrapper.eq(OrderInfo::getDriverId, updateOrderBillForm.getDriverId());
        // 更新字段
        OrderInfo updateOrderInfo = new OrderInfo();
        updateOrderInfo.setStatus(OrderStatus.END_SERVICE.getStatus());
        updateOrderInfo.setRealAmount(updateOrderBillForm.getTotalAmount());
        updateOrderInfo.setFavourFee(updateOrderBillForm.getFavourFee());
        updateOrderInfo.setEndServiceTime(new Date());
        updateOrderInfo.setRealDistance(updateOrderBillForm.getRealDistance());
        // 只能更新自己的订单
        int row = orderInfoMapper.update(updateOrderInfo, queryWrapper);
        if (row == 1) {
            // 记录日志
            this.log(updateOrderBillForm.getOrderId(), OrderStatus.END_SERVICE.getStatus());
            // 插入实际账单数据
            OrderBill orderBill = new OrderBill();
            BeanUtils.copyProperties(updateOrderBillForm, orderBill);
            orderBill.setOrderId(updateOrderBillForm.getOrderId());
            orderBill.setPayAmount(orderBill.getTotalAmount());
            orderBillMapper.insert(orderBill);
            // 插入分账信息数据
            OrderProfitSharing orderProfitSharing = new OrderProfitSharing();
            BeanUtils.copyProperties(updateOrderBillForm, orderProfitSharing);
            orderProfitSharing.setOrderId(updateOrderBillForm.getOrderId());
            orderProfitSharing.setRuleId(updateOrderBillForm.getProfitSharingRuleId());
            orderProfitSharing.setStatus(1);
            orderProfitSharingMapper.insert(orderProfitSharing);
        } else
            throw new PowerException(ResultCodeEnum.UPDATE_ERROR);
        return true;
    }
}